<!-- <div id="app">
  <p>{{message}}</p>
  <input type="text" v-model="message">
  <span v-bind:title="message">
      Hover your mouse over me for a few seconds
      to see my dynamically bound title!
  </span>
  <button v-on:click="sayHi">show message</button>
</div> -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>井字棋游戏</title>
  <style>
    body {
      font: 14px "Century Gothic", Futura, sans-serif;
      margin: 20px;
    }

    ol, ul {
      padding-left: 30px;
    }

    .board-row:after {
      clear: both;
      content: "";
      display: table;
    }

    .status {
      margin-bottom: 10px;
    }

    .square {
      background: #fff;
      border: 1px solid #999;
      float: left;
      font-size: 24px;
      font-weight: bold;
      line-height: 34px;
      height: 34px;
      margin-right: -1px;
      margin-top: -1px;
      padding: 0;
      text-align: center;
      width: 34px;
    }

    .square:focus {
      outline: none;
    }

    .kbd-navigation .square:focus {
      background: #ddd;
    }

    .game {
      display: flex;
      flex-direction: row;
    }

    .game-info {
      margin-left: 20px;
    }  
  </style>
</head>
<body>
  <div id="app">
    <div class="game">
      <div class="game-board" v-bind:title="status">
        <div>
          <div class="board-row">
            <button class="square" v-on:click="handleClick(0)">
              {{squares[0]}}
            </button>
            <button class="square" v-on:click="handleClick(1)">
              {{squares[1]}}
            </button>
            <button class="square" v-on:click="handleClick(2)">
              {{squares[2]}}
            </button>
          </div>
          <div class="board-row">
            <button class="square" v-on:click="handleClick(3)">
              {{squares[3]}}
            </button>
            <button class="square" v-on:click="handleClick(4)">
              {{squares[4]}}
            </button>
            <button class="square" v-on:click="handleClick(5)">
              {{squares[5]}}
            </button>
          </div>
          <div class="board-row">
            <button class="square" v-on:click="handleClick(6)">
              {{squares[6]}}
            </button>
            <button class="square" v-on:click="handleClick(7)">
              {{squares[7]}}
            </button>
            <button class="square" v-on:click="handleClick(8)">
              {{squares[8]}}
            </button>
          </div>
        </div>
      </div>
      <div class="game-info">
        <div>{{status}}</div>
        <button v-on:click="reset">重置</button>
        <button v-on:click="playWithComputer(event)">手动模式</button>
        <p>游戏说明：'X'和'O'依次落子，首先连成一条线的一方获胜，可通过按钮切换模式</p>
      </div>
    </div>
  </div>
</body>
</html>

<script type="module">
  import {ToyVue as Vue} from "./toy_vue.js"

  var app = new Vue({
    el: "#app", 
    data: {
      xIsNext: true,
      status: "Next player: X",
      squares: Array(9).fill(null),
      winner: null,
      autoMode: false,
    },
    methods: {
      handleClick(i) {
          return () => {
            // 获胜或已走过的直接返回
            if (this.winner || this.squares[i]) {
              return 
            }
            // 更新棋局
            // let newArrProp = Array(9).fill(null)
            // for(let i=0; i<9; i++) {
            //   newArrProp[i] = this.squares[i]
            // }
            // newArrProp[i] = this.xIsNext ? 'X' : 'O'
            // this.squares = newArrProp
            this.squares[i] = this.xIsNext ? 'X' : 'O'
            this.squares = [...this.squares]
            this.xIsNext = !this.xIsNext
            // 判断对方是否会赢
            if(willWin(this.squares, this.xIsNext)) console.log(this.xIsNext ? "X will win":"O will win")

            this.winner = calculateWinner(this.squares)
            if(this.winner) {
              this.status = 'Winner: ' + this.winner;  
            }else if(!this.squares.includes(null)){
              this.status = 'play even'
            }else{
              this.status = 'Next player: ' + (this.xIsNext ? 'X':'O');    
            }

            if(this.autoMode) {
              setTimeout(computerMove.bind(this), 500)
            }
          }
      },
      reset(){
        return () => {
          this.xIsNext = true
          this.status = "Next player: X"
          this.squares = new Array(9).fill(null)
          this.winner = null
        }
      },
      playWithComputer(event) {
        return (event)=>{
          this.autoMode = !this.autoMode
          console.log(event.target.value)
          event.target.innerText = this.autoMode ? "人机模式":"手动模式"
        }
      }
    }
  })

  function calculateWinner(squares) {
    const lines = [
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8],
      [0, 3, 6],
      [1, 4, 7],
      [2, 5, 8],
      [0, 4, 8],
      [2, 4, 6],
    ];
    for (let i = 0; i < lines.length; i++) {
      const [a, b, c] = lines[i];
      if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
        return squares[a];
      }
    }
    return null;
  }

  function copy(pattern) {
//      return JSON.parse(JSON.stringify(pattern))
      return Object.create(pattern)
    }

  // 预测是否要赢，返回要赢该走的位置
  function willWin(pattern, xIsNext) {
    for(let i=0; i<3; i++) {
      for(let j=0; j<3; j++) {
        if(pattern[3*i+j]) {
          continue
        }
        let patternCopy = copy(pattern)
        patternCopy[3*i+j] = xIsNext ? 'X':'O'
        if(calculateWinner(patternCopy)) {
          return [i, j]
        }
      }
    }
    return null
  }   

   // 获得当前方最好的策略和相应预测结果
   function bestChoice(pattern, xIsNext) {
      let p 
      if(p = willWin(pattern, xIsNext)) {
        return {
          point: p,
          result: 1
        }
      }
      // 模拟一轮对弈，确定预测结果（对对方最差的策略就是对己方最好的策略）
      let result = -2
      p = null 
      outer: for(let i=0; i<3; i++) {
              for(let j=0; j<3; j++) {
                if(pattern[3*i+j]) {
                  continue
                }
                let tmp = copy(pattern)
                tmp[3*i+j] = xIsNext ? 'X':'O'
                let r = bestChoice(tmp, !xIsNext).result
                if(-r > result) {
                  result = -r
                  p = [i, j]
                  // 胜负剪枝
                  if(result == 1) {
                    break outer
                  }
                }
              }
            }
      return {
        point: p,
        result: p ? result : 0
      }
    }    

    function computerMove() {
          if(this.winner != null) return
          let computerChoice = bestChoice(this.squares, this.xIsNext)
          if(computerChoice.point) {
            this.squares[computerChoice.point[0]*3 + computerChoice.point[1]] = this.xIsNext ? 'X' : 'O'  
            this.squares = [...this.squares]       
            this.xIsNext = !this.xIsNext
            // 判断对方是否会赢
            if(willWin(this.squares, this.xIsNext)) console.log(this.xIsNext ? "X will win":"O will win")
    
            this.winner = calculateWinner(this.squares)
            if(this.winner) {
              this.status = 'Winner: ' + this.winner;  
            }else if(!this.squares.includes(null)){
              this.status = 'play even'
            }else{
              this.status = 'Next player: ' + (this.xIsNext ? 'X':'O');    
            }
          }
      }
</script>